"""
高德地图路径规划工具
集成高德地图API，提供步行、骑行、公共交通、驾车四种出行模式的路径规划功能
"""

import os
import json
import requests
import logging
from typing import Dict, List, Any, Optional, Tuple
from dataclasses import dataclass
from dotenv import load_dotenv

from ..utils.logger import setup_logger

# 加载环境变量
load_dotenv()


@dataclass
class RouteInfo:
    """路线信息数据类"""
    distance: str  # 总距离
    duration: str  # 预计耗时
    steps: List[Dict[str, Any]]  # 详细步骤
    cost: Optional[str] = None  # 费用（公共交通）
    tolls: Optional[str] = None  # 过路费（驾车）


class AmapNavigationTool:
    """高德地图路径规划工具"""
    
    def __init__(self):
        """初始化工具"""
        self.logger = setup_logger(__name__)
        self.api_key = os.getenv('AMAP_API_KEY')
        
        if not self.api_key:
            self.logger.error("未找到高德地图API密钥，请在.env文件中配置AMAP_API_KEY")
            raise ValueError("高德地图API密钥未配置")
        
        self.base_url = "https://restapi.amap.com/v3"
        self.logger.info("高德地图路径规划工具初始化完成")
    
    def _make_request(self, endpoint: str, params: Dict[str, Any]) -> Dict[str, Any]:
        """
        发送API请求
        
        Args:
            endpoint: API端点
            params: 请求参数
            
        Returns:
            API响应数据
        """
        try:
            params['key'] = self.api_key
            params['output'] = 'json'
            
            url = f"{self.base_url}/{endpoint}"
            response = requests.get(url, params=params, timeout=10)
            response.raise_for_status()
            
            data = response.json()
            
            if data.get('status') != '1':
                error_msg = data.get('info', '未知错误')
                self.logger.error(f"API请求失败: {error_msg}")
                raise Exception(f"高德地图API错误: {error_msg}")
            
            return data
            
        except requests.exceptions.RequestException as e:
            self.logger.error(f"网络请求失败: {e}")
            raise Exception(f"网络请求失败: {e}")
        except json.JSONDecodeError as e:
            self.logger.error(f"JSON解析失败: {e}")
            raise Exception(f"响应解析失败: {e}")
        except Exception as e:
            self.logger.error(f"API请求异常: {e}")
            raise
    
    def _geocode_address(self, address: str, city: str = None) -> Tuple[float, float]:
        """
        地址转坐标
        
        Args:
            address: 地址
            city: 城市（可选）
            
        Returns:
            (经度, 纬度)
        """
        try:
            params = {
                'address': address,
                'city': city or ''
            }
            
            data = self._make_request('geocode/geo', params)
            geocodes = data.get('geocodes', [])
            
            if not geocodes:
                raise Exception(f"无法解析地址: {address}")
            
            location = geocodes[0]['location']
            lng, lat = map(float, location.split(','))
            
            self.logger.info(f"地址解析成功: {address} -> ({lng}, {lat})")
            return lng, lat
            
        except Exception as e:
            self.logger.error(f"地址解析失败: {e}")
            raise Exception(f"地址解析失败: {e}")
    
    def _format_duration(self, seconds: int) -> str:
        """格式化时长"""
        hours = seconds // 3600
        minutes = (seconds % 3600) // 60
        
        if hours > 0:
            return f"{hours}小时{minutes}分钟"
        else:
            return f"{minutes}分钟"
    
    def _format_distance(self, meters: int) -> str:
        """格式化距离"""
        if meters >= 1000:
            km = meters / 1000
            return f"{km:.1f}公里"
        else:
            return f"{meters}米"
    
    def plan_walking_route(self, origin: str, destination: str, city: str = None) -> RouteInfo:
        """
        规划步行路线
        
        Args:
            origin: 起点地址
            destination: 终点地址
            city: 城市（可选）
            
        Returns:
            步行路线信息
        """
        try:
            self.logger.info(f"开始规划步行路线: {origin} -> {destination}")
            
            # 获取坐标
            origin_lng, origin_lat = self._geocode_address(origin, city)
            dest_lng, dest_lat = self._geocode_address(destination, city)
            
            # 请求步行路线
            params = {
                'origin': f"{origin_lng},{origin_lat}",
                'destination': f"{dest_lng},{dest_lat}",
                'strategy': '10'  # 步行策略
            }
            
            data = self._make_request('direction/walking', params)
            route = data.get('route', {})
            paths = route.get('paths', [])
            
            if not paths:
                raise Exception("未找到步行路线")
            
            path = paths[0]
            steps = []
            
            # 解析步骤
            for step in path.get('steps', []):
                step_info = {
                    'instruction': step.get('instruction', ''),
                    'distance': self._format_distance(int(step.get('distance', 0))),
                    'duration': self._format_duration(int(step.get('duration', 0))),
                    'road': step.get('road', '')
                }
                steps.append(step_info)
            
            route_info = RouteInfo(
                distance=self._format_distance(int(path.get('distance', 0))),
                duration=self._format_duration(int(path.get('duration', 0))),
                steps=steps
            )
            
            self.logger.info(f"步行路线规划完成: {route_info.distance}, {route_info.duration}")
            return route_info
            
        except Exception as e:
            self.logger.error(f"步行路线规划失败: {e}")
            raise Exception(f"步行路线规划失败: {e}")
    
    def plan_cycling_route(self, origin: str, destination: str, city: str = None) -> RouteInfo:
        """
        规划骑行路线
        
        Args:
            origin: 起点地址
            destination: 终点地址
            city: 城市（可选）
            
        Returns:
            骑行路线信息
        """
        try:
            self.logger.info(f"开始规划骑行路线: {origin} -> {destination}")
            
            # 获取坐标
            origin_lng, origin_lat = self._geocode_address(origin, city)
            dest_lng, dest_lat = self._geocode_address(destination, city)
            
            # 请求骑行路线
            params = {
                'origin': f"{origin_lng},{origin_lat}",
                'destination': f"{dest_lng},{dest_lat}",
                'strategy': '10'  # 骑行策略
            }
            
            data = self._make_request('direction/bicycling', params)
            route = data.get('route', {})
            paths = route.get('paths', [])
            
            if not paths:
                raise Exception("未找到骑行路线")
            
            path = paths[0]
            steps = []
            
            # 解析步骤
            for step in path.get('steps', []):
                step_info = {
                    'instruction': step.get('instruction', ''),
                    'distance': self._format_distance(int(step.get('distance', 0))),
                    'duration': self._format_duration(int(step.get('duration', 0))),
                    'road': step.get('road', '')
                }
                steps.append(step_info)
            
            route_info = RouteInfo(
                distance=self._format_distance(int(path.get('distance', 0))),
                duration=self._format_duration(int(path.get('duration', 0))),
                steps=steps
            )
            
            self.logger.info(f"骑行路线规划完成: {route_info.distance}, {route_info.duration}")
            return route_info
            
        except Exception as e:
            self.logger.error(f"骑行路线规划失败: {e}")
            raise Exception(f"骑行路线规划失败: {e}")
    
    def plan_driving_route(self, origin: str, destination: str, city: str = None) -> RouteInfo:
        """
        规划驾车路线
        
        Args:
            origin: 起点地址
            destination: 终点地址
            city: 城市（可选）
            
        Returns:
            驾车路线信息
        """
        try:
            self.logger.info(f"开始规划驾车路线: {origin} -> {destination}")
            
            # 获取坐标
            origin_lng, origin_lat = self._geocode_address(origin, city)
            dest_lng, dest_lat = self._geocode_address(destination, city)
            
            # 请求驾车路线
            params = {
                'origin': f"{origin_lng},{origin_lat}",
                'destination': f"{dest_lng},{dest_lat}",
                'strategy': '0'  # 速度优先
            }
            
            data = self._make_request('direction/driving', params)
            route = data.get('route', {})
            paths = route.get('paths', [])
            
            if not paths:
                raise Exception("未找到驾车路线")
            
            path = paths[0]
            steps = []
            
            # 解析步骤
            for step in path.get('steps', []):
                step_info = {
                    'instruction': step.get('instruction', ''),
                    'distance': self._format_distance(int(step.get('distance', 0))),
                    'duration': self._format_duration(int(step.get('duration', 0))),
                    'road': step.get('road', '')
                }
                steps.append(step_info)
            
            # 获取费用信息
            tolls = path.get('tolls', '0')
            toll_distance = path.get('toll_distance', '0')
            
            route_info = RouteInfo(
                distance=self._format_distance(int(path.get('distance', 0))),
                duration=self._format_duration(int(path.get('duration', 0))),
                steps=steps,
                tolls=f"过路费: {tolls}元 (收费路段: {self._format_distance(int(toll_distance))})"
            )
            
            self.logger.info(f"驾车路线规划完成: {route_info.distance}, {route_info.duration}")
            return route_info
            
        except Exception as e:
            self.logger.error(f"驾车路线规划失败: {e}")
            raise Exception(f"驾车路线规划失败: {e}")
    
    def plan_transit_route(self, origin: str, destination: str, city: str = None) -> RouteInfo:
        """
        规划公共交通路线
        
        Args:
            origin: 起点地址
            destination: 终点地址
            city: 城市（可选）
            
        Returns:
            公共交通路线信息
        """
        try:
            self.logger.info(f"开始规划公共交通路线: {origin} -> {destination}")
            
            # 获取坐标
            origin_lng, origin_lat = self._geocode_address(origin, city)
            dest_lng, dest_lat = self._geocode_address(destination, city)
            
            # 请求公共交通路线
            params = {
                'origin': f"{origin_lng},{origin_lat}",
                'destination': f"{dest_lng},{dest_lat}",
                'city': city or '',
                'strategy': '0'  # 最快捷模式
            }
            
            data = self._make_request('direction/transit/integrated', params)
            route = data.get('route', {})
            transits = route.get('transits', [])
            
            if not transits:
                raise Exception("未找到公共交通路线")
            
            transit = transits[0]
            steps = []
            
            # 解析步骤
            for segment in transit.get('segments', []):
                if segment.get('walking'):
                    # 步行段
                    walking = segment['walking']
                    step_info = {
                        'instruction': f"步行 {self._format_distance(int(walking.get('distance', 0)))}",
                        'distance': self._format_distance(int(walking.get('distance', 0))),
                        'duration': self._format_duration(int(walking.get('duration', 0))),
                        'road': '步行'
                    }
                    steps.append(step_info)
                
                elif segment.get('bus'):
                    # 公交段
                    bus = segment['bus']
                    buslines = bus.get('buslines', [])
                    if buslines:
                        busline = buslines[0]
                        step_info = {
                            'instruction': f"乘坐 {busline.get('name', '')}",
                            'distance': self._format_distance(int(busline.get('distance', 0))),
                            'duration': self._format_duration(int(busline.get('duration', 0))),
                            'road': f"公交: {busline.get('name', '')}"
                        }
                        steps.append(step_info)
                
                elif segment.get('railway'):
                    # 地铁段
                    railway = segment['railway']
                    step_info = {
                        'instruction': f"乘坐地铁 {railway.get('name', '')}",
                        'distance': self._format_distance(int(railway.get('distance', 0))),
                        'duration': self._format_duration(int(railway.get('duration', 0))),
                        'road': f"地铁: {railway.get('name', '')}"
                    }
                    steps.append(step_info)
            
            # 获取费用信息
            cost = transit.get('cost', '0')
            
            route_info = RouteInfo(
                distance=self._format_distance(int(transit.get('distance', 0))),
                duration=self._format_duration(int(transit.get('duration', 0))),
                steps=steps,
                cost=f"费用: {cost}元"
            )
            
            self.logger.info(f"公共交通路线规划完成: {route_info.distance}, {route_info.duration}")
            return route_info
            
        except Exception as e:
            self.logger.error(f"公共交通路线规划失败: {e}")
            raise Exception(f"公共交通路线规划失败: {e}")
    
    def plan_route(self, origin: str, destination: str, mode: str = "walking", city: str = None) -> RouteInfo:
        """
        规划路线（统一接口）
        
        Args:
            origin: 起点地址
            destination: 终点地址
            mode: 出行模式 ("walking", "cycling", "driving", "transit")
            city: 城市（可选）
            
        Returns:
            路线信息
        """
        try:
            self.logger.info(f"开始规划路线: {origin} -> {destination} (模式: {mode})")
            
            if mode == "walking":
                return self.plan_walking_route(origin, destination, city)
            elif mode == "cycling":
                return self.plan_cycling_route(origin, destination, city)
            elif mode == "driving":
                return self.plan_driving_route(origin, destination, city)
            elif mode == "transit":
                return self.plan_transit_route(origin, destination, city)
            else:
                raise ValueError(f"不支持的出行模式: {mode}")
                
        except Exception as e:
            self.logger.error(f"路线规划失败: {e}")
            raise
    
    def format_route_info(self, route_info: RouteInfo) -> str:
        """
        格式化路线信息为可读文本
        
        Args:
            route_info: 路线信息
            
        Returns:
            格式化的路线描述
        """
        try:
            result = []
            result.append(f"总距离: {route_info.distance}")
            result.append(f"预计耗时: {route_info.duration}")
            
            if route_info.cost:
                result.append(f"费用: {route_info.cost}")
            
            if route_info.tolls:
                result.append(f"过路费: {route_info.tolls}")
            
            result.append("\n详细路线:")
            for i, step in enumerate(route_info.steps, 1):
                result.append(f"{i}. {step['instruction']} ({step['distance']}, {step['duration']})")
                if step['road']:
                    result.append(f"   途经: {step['road']}")
            
            return "\n".join(result)
            
        except Exception as e:
            self.logger.error(f"格式化路线信息失败: {e}")
            return f"路线信息格式化失败: {e}"
    
    def get_route_summary(self, origin: str, destination: str, city: str = None) -> Dict[str, Any]:
        """
        获取所有出行模式的路线摘要
        
        Args:
            origin: 起点地址
            destination: 终点地址
            city: 城市（可选）
            
        Returns:
            包含所有出行模式摘要的字典
        """
        try:
            self.logger.info(f"获取路线摘要: {origin} -> {destination}")
            
            summary = {}
            modes = ["walking", "cycling", "driving", "transit"]
            
            for mode in modes:
                try:
                    route_info = self.plan_route(origin, destination, mode, city)
                    summary[mode] = {
                        "distance": route_info.distance,
                        "duration": route_info.duration,
                        "cost": route_info.cost,
                        "tolls": route_info.tolls
                    }
                except Exception as e:
                    self.logger.warning(f"{mode}模式规划失败: {e}")
                    summary[mode] = {"error": str(e)}
            
            return summary
            
        except Exception as e:
            self.logger.error(f"获取路线摘要失败: {e}")
            return {"error": str(e)}
